package cn.factorybox.item.aop;

import cn.factorybox.common.utils.IpUtils;
import cn.factorybox.common.utils.UUIDUtil;
import cn.factorybox.entity.UserInfo;
import cn.factorybox.item.annotation.Log;
import cn.factorybox.item.config.JwtProperties;
import cn.factorybox.item.service.SystemLogService;
import cn.factorybox.model.entity.SystemLog;
import cn.factorybox.utils.JwtUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author flypig
 * @version 1.0
 * @date 2020-04-19 22:42
 */
@Aspect
@Component
@EnableConfigurationProperties(JwtProperties.class) // 启动配置类
public class LogAspect {

    @Autowired
    private JwtProperties jwtProperties;

    @Resource
    private SystemLogService systemLogService;

    /**
     * 此处的切点是注解的方式，也可以用包名的方式达到相同的效果
     * '@Pointcut("execution(* com.wwj.springboot.service.impl.*.*(..))")'
     */
    @Pointcut("@annotation(cn.factorybox.item.annotation.Log)")
    public void operationLog(){}

    /**
     * 环绕增强，相当于MethodInterceptor
     */
    @Around("operationLog()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        Object result = null;
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        HttpServletRequest request = sra.getRequest();
        String token = request.getHeader("token");
        UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getKey());
//        System.out.println("token====" + token);
        // result的值就是被拦截方法的返回值
        try {
            result = pjp.proceed();
            return result;
        } finally {
            try {
                // 方法执行完成后增加日志
                addOperationLog(request,pjp,result,userInfo);
            } catch (Exception e) {
                System.out.println("LogAspect 操作失败：" + e.getMessage());
                e.printStackTrace();
            }
        }
    }

    private void addOperationLog(HttpServletRequest request,JoinPoint joinPoint, Object res, UserInfo userInfo) {
        SystemLog systemLog = new SystemLog();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        systemLog.setId(UUIDUtil.uuid());
        // 获取内网地址IpUtils.intranetIp()
        // 获取外网地址IpUtils.internetIp()
        systemLog.setfUserName(userInfo.getUsername());
        systemLog.setfUserId(userInfo.getId());
        systemLog.setfUserIp(IpUtils.getIpAddr(request));
        systemLog.setfOperationTime(new Date());
        String address = IpUtils.getCityInfo(systemLog.getfUserIp()).replace("|0","");
        systemLog.setfLocation(address);
        Log annotation =  signature.getMethod().getAnnotation(Log.class);
        if (annotation != null) {
            systemLog.setfLogLevel(annotation.level());
            systemLog.setfLogDescribe(getDetail(((MethodSignature)joinPoint.getSignature()).getParameterNames(),joinPoint.getArgs(),annotation));
            systemLog.setfOperationType(annotation.operationType().getValue());
            systemLog.setfOperationUnit(annotation.operationUnit().getValue());
        }
        // 保存日志
        systemLogService.addlog(systemLog);
        System.out.println(systemLog.toString());
    }

    private String getDetail(String[] argNames, Object[] args, Log annotation) {
        Map<Object, Object> map = new HashMap<>(4);
        for(int i = 0;i < argNames.length;i++){
            map.put(argNames[i],args[i]);
//            System.out.println(argNames[i]);
//            System.out.println(args[i]);
        }

        String detail = annotation.detail();
        String type = annotation.operationType().getValue();
        String unit = annotation.operationUnit().getValue();
        if (type.equals("delete")) {
            if (unit.equals("device")) {
                detail = detail + "，设备编号：" + map.get("value");
            }else if (unit.equals("devicedata")) {
                StringBuilder sb = new StringBuilder(detail);
                detail = sb.insert(4,map.get("value").toString() + "日").toString() + "，数据ID：" + map.get("id");
            }
        } else if (type.equals("update")) {
            if (unit.equals("device")) {
                // 获取到requestbody中的设备号
                detail = detail + "，设备编号：" + ((Map)map.get("map")).get("value");
            }
        }
//        System.out.println("detail:" + detail);
        return detail;
    }


    /**
     * 后置异常通知
     */
    @AfterThrowing("operationLog()")
    public void throwss(JoinPoint jp){
        System.out.println("方法异常时执行.....");
    }


//    /**
//     * 后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
//     */
//    @After("operationLog()")
//    public void after(JoinPoint jp){
//        System.out.println("方法最后执行.....");
//    }
}
